﻿using Sidvall.Net;
using Sidvall.Net.Mime;
using Sidvall.Serialization;
using Sidvall.UI.Dialogs;
using Sidvall.UI.Messaging;
using System.Linq;
using System.Threading.Tasks;

namespace Sidvall.UI.ViewModels
{
    public class SecurityControlViewModel : ControlViewModelBase, IViewModel
    {
        #region Public Members

        public Sidvall.UI.Views.IView ViewModelView { get; set; }
        public string ViewModelRegionName { get; set; }

        #region HttpClient

        private IHttpClient _HttpClient;
        public IHttpClient HttpClient
        {
            get
            {
                if (_HttpClient == null)
                {
                    var settings = new HttpClientSettings()
                    {
                        AllowAutoRedirect = false,
                    };
                    settings.ResponseTypes.Clear();
                    settings.ResponseTypes.Add(MediaType.TextHtml);
                    _HttpClient = Sidvall.SystemContext.Current.HttpClientFactory.GetHttpClient(settings);
                }
                return _HttpClient;
            }
            private set
            {
                _HttpClient = value;
            }
        }

        #endregion
        #region Proxy

        private ProxySettings _Proxy;
        public ProxySettings Proxy
        {
            get
            {
                return _Proxy;
            }
            set
            {
                _Proxy = value;
                RaisePropertyChanged(nameof(Proxy));
            }
        }

        #endregion
        #region UserName

        private string _UserName = string.Empty;
        public string UserName
        {
            get
            {
                return _UserName;
            }
            set
            {
                if (value == null)
                    value = string.Empty;
                if (_UserName == value)
                    return;
                _UserName = value;
                RaisePropertyChanged(nameof(UserName));
                RaisePropertyChanged(nameof(CanLogOn));
                RaisePropertyChanged(nameof(IsPrimaryButtonEnabled));
            }
        }

        #endregion
        #region Email

        private string _Email;
        public string Email
        {
            get
            {
                return _Email;
            }
            set
            {
                if (_Email == value)
                    return;
                _Email = value;
                RaisePropertyChanged(nameof(Email));
                RaisePropertyChanged(nameof(CanSendEmail));
                RaisePropertyChanged(nameof(IsPrimaryButtonEnabled));
            }
        }

        #endregion
        #region RememberMe

        private bool _RememberMe;
        public bool RememberMe
        {
            get
            {
                return _RememberMe;
            }
            set
            {
                if (_RememberMe == value)
                    return;
                _RememberMe = value;
                RaisePropertyChanged(nameof(RememberMe));
            }
        }

        #endregion
        #region Code

        private string _Code;
        public string Code
        {
            get
            {
                return _Code;
            }
            set
            {
                if (_Code == value)
                    return;
                _Code = value;
                RaisePropertyChanged(nameof(Code));
                RaisePropertyChanged(nameof(CanSendCode));
                RaisePropertyChanged(nameof(IsPrimaryButtonEnabled));
            }
        }

        #endregion
        #region NewPasswordCode

        private string _NewPasswordCode;
        public string NewPasswordCode
        {
            get
            {
                return _NewPasswordCode;
            }
            set
            {
                if (_NewPasswordCode == value)
                    return;
                _NewPasswordCode = value;
                RaisePropertyChanged(nameof(NewPasswordCode));
                RaisePropertyChanged(nameof(CanResetPassword));
                RaisePropertyChanged(nameof(IsPrimaryButtonEnabled));
            }
        }

        #endregion
        #region LogManager

        private Sidvall.Logging.LogManager _LogManager;
        public Sidvall.Logging.LogManager LogManager
        {
            get
            {
                if (_LogManager != null)
                    return _LogManager;
                return Sidvall.SystemContext.Current.LogManager;
            }
            set
            {
                _LogManager = value;
            }
        }

        #endregion
        #region LogOnDialogContext

        private LogOnDialogContext _LogOnDialogContext;
        public LogOnDialogContext LogOnDialogContext
        {
            get
            {
                return _LogOnDialogContext;
            }
            set
            {
                _LogOnDialogContext = value;
                RaisePropertyChanged(nameof(LogOnDialogContext));
                RaisePropertyChanged(nameof(CanLogOn));
                RaisePropertyChanged(nameof(IsPrimaryButtonEnabled));
            }
        }

        #endregion
        #region LogOffDialogContext

        private LogOffDialogContext _LogOffDialogContext;
        public LogOffDialogContext LogOffDialogContext
        {
            get
            {
                return _LogOffDialogContext;
            }
            set
            {
                _LogOffDialogContext = value;
                RaisePropertyChanged(nameof(LogOffDialogContext));
                RaisePropertyChanged(nameof(CanLogOff));
            }
        }

        #endregion
        #region IdentityProvider

        private Sidvall.UI.Entities.IdentityProvider _IdentityProvider;
        public Sidvall.UI.Entities.IdentityProvider IdentityProvider
        {
            get
            {
                return _IdentityProvider;
            }
            set
            {
                _IdentityProvider = value;
                RaisePropertyChanged(nameof(IdentityProvider));
            }
        }

        #endregion
        #region CanChangePassword

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        public bool CanChangePassword
        {
            get
            {
                if (this.IsBusy)
                    return false;
                if (Sidvall.SystemContext.Current.AccountManager == null)
                    return false;
                return true;
            }
        }

        #endregion
        #region CanLogOff

        public bool CanLogOff
        {
            get
            {
                if (this.IsBusy)
                    return false;
                if (this.LogOffDialogContext == null)
                    return false;
                return true;
            }
        }

        #endregion
        #region CanLogOn

        public bool CanLogOn
        {
            get
            {
                if (this.IsBusy)
                    return false;
                if (this.LogOnDialogContext == null)
                    return false;
                if (string.IsNullOrWhiteSpace(this.UserName))
                    return false;
                return true;
            }
        }

        #endregion
        #region CanSendCode

        public bool CanSendCode
        {
            get
            {
                if (this.IsBusy)
                    return false;
                if (string.IsNullOrWhiteSpace(this.Code))
                    return false;
                return true;
            }
        }

        #endregion
        #region CanSendEmail

        public bool CanSendEmail
        {
            get
            {
                if (this.IsBusy)
                    return false;
                if (string.IsNullOrWhiteSpace(this.Email))
                    return false;
                return true;
            }
        }

        #endregion
        #region CanShowProxySettings

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        public bool CanShowProxySettings
        {
            get
            {
                if (this.IsBusy)
                    return false;
                if (Sidvall.SystemContext.Current.ProxyStrategyManager == null)
                    return false;
                return true;
            }
        }

        #endregion
        #region CanShowIdentityProviders

        public bool CanShowIdentityProviders
        {
            get
            {
                if (this.LogOnDialogContext?.IdentityProviders == null)
                    return false;
                if (this.LogOnDialogContext.IdentityProviders.Count == 0)
                    return false;
                return true;
            }
        }

        #endregion
        #region CanResetPassword

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")]
        public bool CanResetPassword
        {
            get
            {
                if (this.IsBusy)
                    return false;
                if (string.IsNullOrWhiteSpace(this.NewPasswordCode))
                    return false;
                return true;
            }
        }

        #endregion
        #region RequireCode

        private bool _RequireCode;
        public bool RequireCode
        {
            get
            {
                return _RequireCode;
            }
            set
            {
                if (_RequireCode == value)
                    return;
                _RequireCode = value;
                RaisePropertyChanged(nameof(RequireCode));
            }
        }

        #endregion
        #region ResourceKeyManager

        private Sidvall.Resources.ResourceKeyManager _ResourceKeyManager;
        public Sidvall.Resources.ResourceKeyManager ResourceKeyManager
        {
            get
            {
                if (_ResourceKeyManager == null)
                    this.ResourceKeyManager = new Sidvall.Resources.ResourceKeyManager();
                return _ResourceKeyManager;
            }
            set
            {
                _ResourceKeyManager = value;
                RaisePropertyChanged(nameof(ResourceKeyManager));
            }
        }

        #endregion
        #region ViewType

        private SecurityControlViewType _ViewType;
        public SecurityControlViewType ViewType
        {
            get
            {
                return _ViewType;
            }
            set
            {
                if (_ViewType == value)
                    return;
                _ViewType = value;
                RaisePropertyChanged(nameof(ViewType));
                RaisePropertyChanged(nameof(ViewTitle));
                RaisePropertyChanged(nameof(PrimaryButtonText));
                RaisePropertyChanged(nameof(SecondaryButtonText));
                RaisePropertyChanged(nameof(IsPrimaryButtonEnabled));
                RaisePropertyChanged(nameof(IsSecondaryButtonEnabled));
            }
        }

        #endregion
        #region ViewTitle

        public string ViewTitle
        {
            get
            {
                switch (this.ViewType)
                {
                    case SecurityControlViewType.LogOffView:
                        return Sidvall.Resources.ResourceKeyManager.Current.SecurityControlLogOffTitle;
                    case SecurityControlViewType.LogOnView:
                        return Sidvall.Resources.ResourceKeyManager.Current.SecurityControlLogOnTitle;
                    case SecurityControlViewType.SubmitCodeView:
                        return Sidvall.Resources.ResourceKeyManager.Current.SecurityControlSubmitCodeTitle;
                    case SecurityControlViewType.ResetPasswordView:
                        return Sidvall.Resources.ResourceKeyManager.Current.SecurityControlResetPasswordTitle;
                    case SecurityControlViewType.NewPasswordEmailView:
                        return Sidvall.Resources.ResourceKeyManager.Current.SecurityControlNewPasswordEmailTitle;
                    case SecurityControlViewType.NewPasswordCodeView:
                        return Sidvall.Resources.ResourceKeyManager.Current.SecurityControlNewPasswordCodeTitle;
                    case SecurityControlViewType.ProxyView:
                        return Sidvall.Resources.ResourceKeyManager.Current.SecurityControlProxyTitle;
                    case SecurityControlViewType.IdentityProviderView:
                        return this.IdentityProvider?.Name;
                    default:
                        return string.Empty;
                }
            }
        }

        #endregion
        #region PrimaryButtonText

        public string PrimaryButtonText
        {
            get
            {
                switch (this.ViewType)
                {
                    case SecurityControlViewType.LogOnView:
                        return Sidvall.Resources.ResourceKeyManager.Current.SecurityControlLogOnButton;
                    case SecurityControlViewType.SubmitCodeView:
                        return Sidvall.Resources.ResourceKeyManager.Current.SecurityControlSubmitButton;
                    case SecurityControlViewType.ResetPasswordView:
                        return Sidvall.Resources.ResourceKeyManager.Current.SecurityControlSendEmailButton;
                    case SecurityControlViewType.NewPasswordEmailView:
                        return Sidvall.Resources.ResourceKeyManager.Current.SecurityControlBackButton;
                    case SecurityControlViewType.NewPasswordCodeView:
                        return Sidvall.Resources.ResourceKeyManager.Current.SecurityControlSubmitButton;
                    case SecurityControlViewType.ProxyView:
                        return Sidvall.Resources.ResourceKeyManager.Current.SecurityControlBackButton;
                    default:
                        return string.Empty;
                }
            }
        }

        #endregion
        #region SecondaryButtonText

        public string SecondaryButtonText
        {
            get
            {
                switch (this.ViewType)
                {
                    case SecurityControlViewType.LogOnView:
                        return Sidvall.Resources.ResourceKeyManager.Current.SecurityControlCloseButton;
                    case SecurityControlViewType.SubmitCodeView:
                        return Sidvall.Resources.ResourceKeyManager.Current.SecurityControlCloseButton;
                    case SecurityControlViewType.ResetPasswordView:
                        return Sidvall.Resources.ResourceKeyManager.Current.SecurityControlCloseButton;
                    case SecurityControlViewType.NewPasswordEmailView:
                        return Sidvall.Resources.ResourceKeyManager.Current.SecurityControlCloseButton;
                    case SecurityControlViewType.NewPasswordCodeView:
                        return Sidvall.Resources.ResourceKeyManager.Current.SecurityControlCloseButton;
                    case SecurityControlViewType.ProxyView:
                        return Sidvall.Resources.ResourceKeyManager.Current.SecurityControlCloseButton;
                    default:
                        return string.Empty;
                }
            }
        }

        #endregion
        #region IsPrimaryButtonEnabled

        public bool IsPrimaryButtonEnabled
        {
            get
            {
                if (this.IsBusy)
                    return false;
                switch (this.ViewType)
                {
                    case SecurityControlViewType.LogOnView:
                        return this.CanLogOn;
                    case SecurityControlViewType.SubmitCodeView:
                        return this.CanSendCode;
                    case SecurityControlViewType.ResetPasswordView:
                        return this.CanSendEmail;
                    case SecurityControlViewType.NewPasswordCodeView:
                        return this.CanResetPassword;
                    default:
                        return true;
                }
            }
        }

        #endregion
        #region IsSecondaryButtonEnabled

        public bool IsSecondaryButtonEnabled
        {
            get
            {
                if (this.IsBusy)
                    return false;
                switch (this.ViewType)
                {
                    default:
                        return true;
                }
            }
        }

        #endregion
        #region ViewModelSettings

        private SecurityControlViewModelSettings _ViewModelSettings;
        public SecurityControlViewModelSettings ViewModelSettings
        {
            get
            {
                return _ViewModelSettings;
            }
            set
            {
                _ViewModelSettings = value;
            }
        }

        #endregion


        #region OnIsBusyChanged

        protected override void OnIsBusyChanged(bool isBusy, string message, string scope)
        {
            base.OnIsBusyChanged(isBusy, message, scope);
            RaisePropertyChanged(nameof(CanChangePassword));
            RaisePropertyChanged(nameof(CanLogOff));
            RaisePropertyChanged(nameof(CanLogOn));
            RaisePropertyChanged(nameof(CanSendCode));
            RaisePropertyChanged(nameof(CanSendEmail));
            RaisePropertyChanged(nameof(CanShowProxySettings));
            RaisePropertyChanged(nameof(CanShowIdentityProviders));
            RaisePropertyChanged(nameof(CanResetPassword));
            RaisePropertyChanged(nameof(IsPrimaryButtonEnabled));
            RaisePropertyChanged(nameof(IsSecondaryButtonEnabled));
        }

        #endregion
        #region OnViewEventAsync

        protected virtual Task OnViewEventAsync(Sidvall.UI.Views.ViewEventArgs args)
        {
            if (args == null)
                throw new System.ArgumentNullException(nameof(args));
            switch (args.EventType)
            {
                case Sidvall.UI.Views.ViewEventType.ViewUnloaded:
                    UnloadViewModel();
                    break;
                default:
                    break;
            }
            return Task.FromResult(true);
        }

        #endregion

        // Commands
        #region InitializeContextAsync

        public async Task InitializeContextAsync(LogOnDialogContext logOnContext, LogOffDialogContext logOffContext)
        {
            await InitializeContextAsync(logOnContext, logOffContext, null);
        }
        public async Task InitializeContextAsync(LogOnDialogContext logOnContext, LogOffDialogContext logOffContext, SecurityControlViewModelSettings viewModelSettings)
        {
            if (viewModelSettings == null)
            {
                viewModelSettings = new SecurityControlViewModelSettings()
                {
                    SendCodeInResetPasswordEmail = false,
                };
            }

            this.LogOffDialogContext = logOffContext;
            this.LogOnDialogContext = logOnContext;
            this.ViewModelSettings = viewModelSettings;
            if (logOnContext != null)
                await InitializeUserResponseAsync(logOnContext.UserResponse);
        }

        #endregion
        #region InitializeIdentityProvider

        public void InitializeIdentityProvider(string key)
        {
            if (!this.CanShowIdentityProviders)
                this.IdentityProvider = null;
            if (string.IsNullOrWhiteSpace(key))
                this.IdentityProvider = null;
            this.IdentityProvider = (from o in this.LogOnDialogContext.IdentityProviders
                                     where o.Key == key
                                     select o).FirstOrDefault();
        }

        #endregion
        #region InitializeProxy

        public void InitializeProxy()
        {
            Sidvall.Net.HttpSystemContext.Current.InitializeProxy(this.Proxy);
            this.HttpClient = null;
        }

        #endregion
        #region InitializeUserResponseAsync

        public async Task InitializeUserResponseAsync(string userResponse)
        {
            if (Sidvall.SystemContext.Current.UserResponseStrategyManager != null)
            {
                if (string.IsNullOrWhiteSpace(userResponse))
                {
                    if (Sidvall.SystemContext.Current.UserResponseStrategyManager.CurrentUserResponse == null)
                        await Sidvall.SystemContext.Current.UserResponseStrategyManager.LoadUserResponseAsync();
                    userResponse = Sidvall.SystemContext.Current.UserResponseStrategyManager.CurrentUserResponse;
                }
            }
            var response = Sidvall.Security.UserResponse.Deserialize(userResponse);
            this.UserName = response.UserName;
            this.RememberMe = response.RememberMe;
        }

        #endregion
        #region LogOffAsync

        public async Task LogOffAsync()
        {
            if (!this.CanLogOff)
                return;
            try
            {
                using (var busyManager = new Sidvall.Data.BusyManager(this))
                {
                    // Initiate logoff
                    var authenticationClient = Sidvall.SystemContext.Current.AuthenticationManager.GetAuthenticationClient(this.LogOffDialogContext.LogOffEndpoint);
                    var startUrl = authenticationClient.CreateLogOffAddress(this.LogOffDialogContext.IdentityToken,
                        this.LogOffDialogContext.RedirectAddress);
                    var response = await this.HttpClient.GetAsync(startUrl);

                    // Process response
                    this.LogOffDialogContext.Response = null;
                    var location = new System.Uri(startUrl);
                    do
                    {
                        if (response.StatusCode == System.Net.HttpStatusCode.Found)
                        {
                            if (response.Headers.Location != null)
                                location = response.Headers.Location;
                            response = await this.HttpClient.GetAsync(location, HttpCompletionOption.ResponseContentRead, System.Threading.CancellationToken.None);
                        }
                        else if (location.ToString().StartsWith(this.LogOffDialogContext.RedirectAddress, System.StringComparison.OrdinalIgnoreCase))
                        {
                            this.LogOffDialogContext.Response = location.AbsoluteUri;
                        }
                        else
                        {
                            var content = await response.GetContentAsStringAsync();
                            if (content.Contains("you are now logged out", System.StringComparison.OrdinalIgnoreCase))
                            {
                                this.LogOffDialogContext.Response = "logged out";
                            }
                            else
                            {
                                this.LogOffDialogContext.Response = "not logged out";
                            }
                        }
                    } while (string.IsNullOrWhiteSpace(this.LogOffDialogContext.Response));
                }
            }
            catch (System.Exception ex)
            {
                await LogAsync(ex);
            }
        }

        #endregion
        #region LogOnAsync

        public async Task LogOnAsync(string password)
        {
            await LogOnAsync(password, false);
        }
        public async Task LogOnAsync(string password, bool byForce)
        {
            if ((!byForce) && (!this.CanLogOn))
                return;
            if (string.IsNullOrWhiteSpace(password))
                return;

            var startUrl = string.Empty;
            try
            {
                using (var busyManager = new Sidvall.Data.BusyManager(this))
                {
                    // Initiate logon
                    var responseItem = await InitiateLogOnAsync();

                    // Logon
                    var pos1 = responseItem.Content.IndexOf("name&quot;:&quot;idsrv.xsrf&quot;,&quot;value&quot;:&quot;");
                    pos1 = pos1 + "name&quot;:&quot;idsrv.xsrf&quot;,&quot;value&quot;:&quot;".Length;
                    var pos2 = responseItem.Content.IndexOf("&quot;", pos1 + 1);
                    var xsrf = responseItem.Content.Substring(pos1, pos2 - pos1);
                    responseItem.Content = "idsrv.xsrf=" + xsrf + "&username=" + System.Net.WebUtility.UrlEncode(this.UserName) + "&password=" + System.Net.WebUtility.UrlEncode(password);
                    responseItem.Response = await this.HttpClient.PostAsync(responseItem.Location, responseItem.Content, MediaType.ApplicationFormUrlEncoded, System.Threading.CancellationToken.None);

                    // Process response
                    await ProcessResponseAsync(ActionType.LogOn, responseItem.Response, responseItem.Location);
                }
            }
            catch (System.Exception ex)
            {
                var message = Sidvall.SystemContext.Current.SystemExceptionManager.GetMessage(ex);
                message = "User name: " + this.UserName +
                    System.Environment.NewLine + System.Environment.NewLine +
                    "Address: " + startUrl +
                    System.Environment.NewLine + System.Environment.NewLine +
                    message;
                await LogAsync(ex.Message, message, Logging.EventType.Error);
                await Sidvall.UI.SystemContext.Current.DialogManager.ShowDialogErrorMessageAsync(ex);
            }
        }

        #endregion
        #region SendCodeAsync

        public async Task SendCodeAsync()
        {
            string content;

            if (!this.CanSendCode)
                return;
            try
            {
                using (var busyManager = new Sidvall.Data.BusyManager(this))
                {
                    // Submit code
                    if (!string.IsNullOrWhiteSpace(this.RequestVerificationToken))
                        content = "__RequestVerificationToken=" + this.RequestVerificationToken + "&code=" + this.Code;
                    else
                        content = "code=" + this.Code;
                    var response = await this.HttpClient.PostAsync(this.CodeLocation, content, MediaType.ApplicationFormUrlEncoded, System.Threading.CancellationToken.None);

                    // Process response
                    await ProcessResponseAsync(ActionType.SendCode, response, this.CodeLocation);
                }
            }
            catch (System.Exception ex)
            {
                await LogAsync(ex);
                await Sidvall.UI.SystemContext.Current.DialogManager.ShowDialogErrorMessageAsync(ex);
            }
        }

        #endregion
        #region SendResetPasswordEmailAsync

        public async Task SendResetPasswordEmailAsync()
        {
            if (!this.CanSendEmail)
                return;
            try
            {
                using (var busyManager = new Sidvall.Data.BusyManager(this))
                {
                    await Sidvall.SystemContext.Current.AccountManager.SendResetPasswordEmailAsync(this.Email);
                }
                if (string.IsNullOrWhiteSpace(this.UserName))
                    this.UserName = this.Email;
            }
            catch (System.Exception ex)
            {
                await LogAsync(ex);
                await Sidvall.UI.SystemContext.Current.DialogManager.ShowDialogErrorMessageAsync(ex);
            }
        }

        #endregion
        #region ResetPasswordAsync

        public async Task<bool> ResetPasswordAsync(string password1, string password2)
        {
            return await ResetPasswordAsync(password1, password2, false);
        }
        public async Task<bool> ResetPasswordAsync(string password1, string password2, bool byForce)
        {
            if ((!byForce) && (!this.CanResetPassword))
                return false;
            if (string.IsNullOrWhiteSpace(password1))
                return false;
            if (string.IsNullOrWhiteSpace(password2))
                return false;
            if (password1 != password2)
                return false;

            try
            {
                using (var busyManager = new Sidvall.Data.BusyManager(this))
                {
                    await Sidvall.SystemContext.Current.AccountManager.ResetPasswordAsync(this.Email, this.NewPasswordCode, password1);
                }

                return true;
            }
            catch (System.Exception ex)
            {
                var message = Sidvall.SystemContext.Current.SystemExceptionManager.GetMessage(ex);
                await LogAsync(ex.Message, message, Logging.EventType.Error);
                await Sidvall.UI.SystemContext.Current.DialogManager.ShowDialogErrorMessageAsync(ex);
            }
            return false;
        }

        #endregion
        #region CallIdentityProviderAsync

        public async Task CallIdentityProviderAsync()
        {
            HttpResponseItem responseItem;

            if (this.IdentityProvider == null)
                return;

            responseItem = null;
            try
            {
                using (var busyManager = new Sidvall.Data.BusyManager(this))
                {
                    // Initiate logon
                    responseItem = await InitiateLogOnAsync();

                    // Call external authorization server
                    var pos1 = responseItem.Content.LastIndexOf("&quot;" + this.IdentityProvider.Key + "&quot;");
                    pos1 = responseItem.Content.IndexOf("&quot;href&quot;:&quot;", pos1);
                    pos1 = pos1 + "&quot;href&quot;:&quot;".Length;
                    var pos2 = responseItem.Content.IndexOf("&quot;", pos1 + 1);
                    var startUrl = responseItem.Content.Substring(pos1, pos2 - pos1).Replace("&amp;", "&");
                    var response = await this.HttpClient.GetAsync(startUrl);
                    var location = new System.Uri(startUrl);
                    while (response.StatusCode == System.Net.HttpStatusCode.Found)
                    {
                        location = response.Headers.Location;
                        response = await this.HttpClient.GetAsync(location, HttpCompletionOption.ResponseContentRead, System.Threading.CancellationToken.None);
                    }
                    var content = await response.GetContentAsStringAsync();
                    responseItem = new HttpResponseItem()
                    {
                        Response = response,
                        Location = location,
                        Content = content,
                    };
                    responseItem = await this.IdentityProvider.DialogManager.CallIdentityProviderAsync(this.HttpClient, responseItem);

                    // Process response
                    await ProcessResponseAsync(ActionType.LogOn, responseItem.Response, responseItem.Location);
                }
            }
            catch (System.Exception ex)
            {
                if (responseItem != null)
                {
                    var message = "Content: " + responseItem.Content +
                         System.Environment.NewLine + System.Environment.NewLine +
                         "Address: " + responseItem.Location.ToString() +
                         System.Environment.NewLine + System.Environment.NewLine +
                         Sidvall.SystemContext.Current.SystemExceptionManager.GetMessage(ex);
                    await LogAsync(ex.Message, message, Logging.EventType.Error);
                    await Sidvall.UI.SystemContext.Current.DialogManager.ShowDialogErrorMessageAsync(ex);
                }
                else
                {
                    await LogAsync(ex);
                    await Sidvall.UI.SystemContext.Current.DialogManager.ShowDialogErrorMessageAsync(ex);
                }
            }
        }

        #endregion

        #region IViewModel Members

        async Task IViewModel.OnViewEventAsync(Sidvall.UI.Views.ViewEventArgs args)
        {
            await OnViewEventAsync(args);
        }

        #endregion

        #endregion
        #region Private Members

        private System.Uri CodeLocation { get; set; }
        private string RequestVerificationToken { get; set; }
        #region ActionType

        public enum ActionType
        {
            LogOff,
            LogOn,
            SendCode
        }

        #endregion

        #region InitiateLogOnAsync

        private async Task<HttpResponseItem> InitiateLogOnAsync()
        {
            var authenticationClient = Sidvall.SystemContext.Current.AuthenticationManager.GetAuthenticationClient(this.LogOnDialogContext.AuthorizeEndpoint);
            var startUrl = authenticationClient.CreateAuthorizeAddress(this.LogOnDialogContext.ClientId,
               this.LogOnDialogContext.ResponseType,
               this.LogOnDialogContext.Scope,
               this.LogOnDialogContext.RedirectAddress,
               this.LogOnDialogContext.State,
               this.LogOnDialogContext.Nonce,
               this.LogOnDialogContext.LogOnHint,
               this.LogOnDialogContext.AuthenticationContextReferences,
               this.LogOnDialogContext.Prompt,
               this.LogOnDialogContext.ResponseMode,
               this.LogOnDialogContext.CodeChallenge,
               this.LogOnDialogContext.CodeChallengeMethod,
               this.LogOnDialogContext.AdditionalValues);
            var response = await this.HttpClient.GetAsync(startUrl);

            // Process response
            var location = new System.Uri(startUrl);
            while (response.StatusCode == System.Net.HttpStatusCode.Found)
            {
                location = response.Headers.Location;
                response = await this.HttpClient.GetAsync(location, HttpCompletionOption.ResponseContentRead, System.Threading.CancellationToken.None);
            }
            if (!response.IsSuccessStatusCode)
                throw new Sidvall.Net.HttpException(response.ReasonPhrase, response.StatusCode);

            // Logon
            var content = await response.GetContentAsStringAsync();

            return new HttpResponseItem()
            {
                Response = response,
                Location = location,
                Content = content,
            };
        }

        #endregion
        #region LogAsync

        private async Task LogAsync(System.Exception ex)
        {
            if (this.LogManager != null)
                await this.LogManager.WriteAsync(ex, Sidvall.Logging.LogCategories.Application);
        }
        private async Task LogAsync(string title, string message, Logging.EventType severity)
        {
            if (this.LogManager != null)
                await this.LogManager.WriteAsync(title, message, Sidvall.Logging.LogCategories.Application, severity);
        }

        #endregion
        #region ProcessResponseAsync

        private async Task ProcessResponseAsync(ActionType actionType, HttpResponse response, System.Uri location)
        {
            string content;
            int pos1, pos2;

            this.LogOnDialogContext.AuthorizeResponse = null;
            do
            {
                if (response.Headers.Location != null)
                    location = response.Headers.Location;
                if (location.ToString().StartsWith(this.LogOnDialogContext.RedirectAddress, System.StringComparison.OrdinalIgnoreCase))
                {
                    var userResponse = new Sidvall.Security.UserResponse()
                    {
                        UserName = this.UserName,
                        RememberMe = this.RememberMe,
                    };
                    this.LogOnDialogContext.AuthorizeResponse = Sidvall.SystemContext.Current.AuthenticationManager.ParseAuthorizeResponseFromAddress(location.AbsoluteUri);
                    this.LogOnDialogContext.UserResponse = userResponse.Serialize();
                    this.LogOnDialogContext.StoreResponses = this.RememberMe;
                }
                else if ((location.ToString().EndsWith("smscode", System.StringComparison.OrdinalIgnoreCase)) && (response.StatusCode == System.Net.HttpStatusCode.OK))
                {
                    this.CodeLocation = location;
                    content = await response.GetContentAsStringAsync();
                    pos1 = content.IndexOf("__RequestVerificationToken");
                    pos1 = content.IndexOf(@"value=""", pos1 + 1);
                    pos1 = pos1 + @"value=""".Length;
                    pos2 = content.IndexOf(@"""", pos1 + 1);
                    this.RequestVerificationToken = content.Substring(pos1, pos2 - pos1);
                    this.RequireCode = true;
                    return;
                }
                else if (response.StatusCode == System.Net.HttpStatusCode.Found)
                {
                    response = await this.HttpClient.GetAsync(location, HttpCompletionOption.ResponseContentRead, System.Threading.CancellationToken.None);
                }
                else
                {
                    switch (actionType)
                    {
                        case ActionType.LogOff:
                            break;
                        case ActionType.LogOn:
                            throw new Sidvall.Security.UnauthenticatedException("Invalid credentials");
                        case ActionType.SendCode:
                            throw new Sidvall.Security.UnauthenticatedException("Invalid code");
                        default:
                            throw new Sidvall.Security.UnauthenticatedException("Invalid action");
                    }
                }
            } while (this.LogOnDialogContext.AuthorizeResponse == null);
        }

        #endregion

        #endregion
        #region Constructors

        public SecurityControlViewModel()
        {
            this.Proxy = Sidvall.Net.HttpSystemContext.Current.GetDefaultProxy();
        }

        #endregion
    }
}
